﻿// <copyright file="PuzzleShape.cs" company="ThorIndustry">Copyright (c) ThorIndustry. All rights reserved.</copyright>

using System.Collections.Generic;

public class PuzzleShape : IWorldVerticeProvider
{
    private Polygon polygon;

    public PuzzleShape(Polygon polygon)
    {
        this.polygon = polygon;
    }

    public string Name
    {
        get
        {
            return this.polygon.Name;
        }
    }

    public UnityEngine.Vector2[] Points
    {
        get
        {
            return this.polygon.Points;
        }
    }

    public UnityEngine.Vector3 CurrentPosition
    {
        get;
        private set;
    }

    public float CurrentRotation
    {
        get;
        private set;
    }

    public bool Flipped
    {
        get;
        private set;
    }

    public UnityEngine.Vector3[] Vertices
    {
        get;
        private set;
    }

    public UnityEngine.Vector3[] WorldVertices
    {
        get;
        private set;
    }

    public int[] Triangles
    {
        get;
        private set;
    }

    public void ChangePosition(UnityEngine.Vector3 newPosition, float angle, bool flipped)
    {
        this.CurrentPosition = newPosition;
        this.CurrentRotation = angle;
        this.Flipped = flipped;

        // Should we notify the change?
        this.WorldTransform();
    }

    public void ChangePosition(PuzzleShapePosition newPosition)
    {
        this.CurrentPosition = new UnityEngine.Vector3(newPosition.Position.X, newPosition.Position.Y);
        this.CurrentRotation = newPosition.Rotation;
        this.Flipped = newPosition.Flipped;

        // Should we notify the change?
        this.WorldTransform();
    }

    public void Initialize()
    {
        this.Vertices = new UnityEngine.Vector3[this.Points.Length];
        this.WorldVertices = new UnityEngine.Vector3[this.Points.Length];
        for (int index = 0; index < this.Vertices.Length; ++index)
        {
            this.Vertices[index] = new UnityEngine.Vector3(this.Points[index].x, this.Points[index].y, 0.01f);
        }

        this.WorldTransform();

        this.Triangles = Helpers.Triangulate(this.polygon.Points);
    }

    public bool IsPointInShape(UnityEngine.Vector3 point)
    {
        float minX = this.WorldVertices[0].x;
        float maxX = this.WorldVertices[0].x;
        float minY = this.WorldVertices[0].y;
        float maxY = this.WorldVertices[0].y;

        for (int i = 1; i < this.WorldVertices.Length; i++)
        {
            UnityEngine.Vector3 vertice = this.WorldVertices[i];
            minX = UnityEngine.Mathf.Min(vertice.x, minX);
            maxX = UnityEngine.Mathf.Max(vertice.x, maxX);
            minY = UnityEngine.Mathf.Min(vertice.y, minY);
            maxY = UnityEngine.Mathf.Max(vertice.y, maxY);
        }

        if (point.x < minX || point.x > maxX || point.y < minY || point.y > maxY)
        {
            return false;
        }
        
        // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
        bool inside = false;
        for (int i = 0, j = this.WorldVertices.Length - 1; i < this.WorldVertices.Length; j = i++)
        {
            if ((this.WorldVertices[i].y >= point.y) != (this.WorldVertices[j].y >= point.y) &&
                 point.x <= ((this.WorldVertices[j].x - this.WorldVertices[i].x) * (point.y - this.WorldVertices[i].y) / (this.WorldVertices[j].y - this.WorldVertices[i].y)) + this.WorldVertices[i].x)
            {
                inside = !inside;
            }
        }
        
        return inside;
    }

    private void WorldTransform()
    {
        // Based on the position, the rotation and the flip, update the vertice worldposition.
        float flipRotation = this.Flipped ? 180 : 0;
        UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.Euler(0, flipRotation, this.CurrentRotation);
        for (int index = 0; index < this.Vertices.Length; ++index)
        {
            this.WorldVertices[index] = this.CurrentPosition + (quaternion * this.Vertices[index]);
        }
    }
}
